﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FarseerPhysics.Dynamics;

namespace MapLibrary.Players.CollisionResponse
{
    /// <summary>
    /// The CollisionResponseManager handles all collision responses for a Sprite.
    /// It contains a mapping of CollisionCategory -> CollisionAction.  When a collision
    /// of a certain category is triggered, the corresponding CollisionAction will be
    /// notified that the collision occured.  Then the CollisionAction will execute
    /// all of its CollisionBehaviors, changing the sprite in some way.
    /// </summary>
    public class CollisionResponseManager
    {
        /// <summary>
        /// Different collision categories.  Feel free to extend this for new
        /// different collisions.
        /// </summary>
        public enum CollisionCategory
        {
            None = Category.None,
            Player = Category.Cat1,
            Tuberculosis = Category.Cat2,
            HIV = Category.Cat3,
            Malaria = Category.Cat4,
            Floor = Category.Cat5,
            Mucus = Category.Cat6,
            Particle = Category.Cat7,
            Bullet = Category.Cat8,
            TuberculosisSpit = Category.Cat9,
            Enemy = Tuberculosis | HIV | Malaria,
            All = Category.All
        }

        /// <summary>
        /// There is a one to one correspondence between the elements of this list.  In other words,
        /// the CollisionCategory located at position i in cateogryList corresponds directly to
        /// the CollisionResponse located at position i in collisionResponseList.
        /// </summary>
        private List<CollisionAction> collisionResponseList;
        private List<CollisionCategory> categoryList;

        private List<CollisionCategory> categoriesTriggeredThisFrame;

        public CollisionResponseManager()
        {
            collisionResponseList = new List<CollisionAction>();
            categoryList = new List<CollisionCategory>();
            categoriesTriggeredThisFrame = new List<CollisionCategory>();
        }

        public void AddCollisionAction(CollisionCategory cat, CollisionAction action)
        {
            categoryList.Add(cat);
            collisionResponseList.Add(action);
        }

        /// <summary>
        /// Tell the collision manager that a certain collision has occured.  The collision
        /// manager will then return with a boolean telling whether or not to count the collision.
        /// Then when the manager is updated at a later time, the Owner sprite will be updated.
        /// </summary>
        /// <param name="category"></param>
        /// <returns></returns>
        public bool AddCollisionThisFrame(CollisionCategory category)
        {
            categoriesTriggeredThisFrame.Add(category);

            return GetCollisionResolution(category);
        }

        private bool GetCollisionResolution(CollisionCategory category)
        {
            bool toReturn = true;
            for (int i = 0; i < categoryList.Count; i++)
            {
                if ((categoryList[i] & category) != 0)
                    toReturn &= collisionResponseList[i].CollisionResolution;
            }
            return toReturn;
        }

        public void Update()
        {
            foreach (CollisionAction r in collisionResponseList)
            {
                r.Update(categoriesTriggeredThisFrame);
            }

            categoriesTriggeredThisFrame.Clear();
        }
    }
}
